---
title: Utilities
description: Utilities for working with query strings
---

## Serializer helper

<FeatureSupportMatrix introducedInVersion='1.16.0' hideFrameworks />

To populate `<Link>{:tsx}` components with state values, you can use the `createSerializer{:ts}`
helper.

Pass it an object describing your search params, and it will give you a function
to call with values, that generates a query string serialized as the hooks would do.

Example:

```ts
// [!code word:createSerializer]
import {
  createSerializer,
  parseAsInteger,
  parseAsIsoDateTime,
  parseAsString,
  parseAsStringLiteral
} from 'nuqs/server' // can also be imported from 'nuqs' in client code

const searchParams = {
  search: parseAsString,
  limit: parseAsInteger,
  from: parseAsIsoDateTime,
  to: parseAsIsoDateTime,
  sortBy: parseAsStringLiteral(['asc', 'desc'])
}

// Create a serializer function by passing the description of the search params to accept
const serialize = createSerializer(searchParams)

// Then later, pass it some values (a subset) and render them to a query string
serialize({
  search: 'foo bar',
  limit: 10,
  from: new Date('2024-01-01'),
  // here, we omit `to`, which won't be added
  sortBy: null // null values are also not rendered
})
// ?search=foo+bar&limit=10&from=2024-01-01T00:00:00.000Z
```

### Base parameter

The returned `serialize{:ts}` function can take a base parameter over which to
append/amend the search params:

```ts
serialize('/path?baz=qux', { foo: 'bar' }) // /path?baz=qux&foo=bar

const search = new URLSearchParams('?baz=qux')
serialize(search, { foo: 'bar' }) // ?baz=qux&foo=bar

const url = new URL('https://example.com/path?baz=qux')
serialize(url, { foo: 'bar' }) // https://example.com/path?baz=qux&foo=bar

// Passing null removes existing values
serialize('?remove=me', { foo: 'bar', remove: null }) // ?foo=bar
```

### Shorter search params keys

Just like with `useQueryStates{:ts}`, you can
define a [`urlKeys{:ts}`](/docs/batching#shorter-search-params-keys)
object to map the variable names defined by the parsers to shorter keys in the URL:

```ts
const serialize = createSerializer(
  {
    // 1. Use variable names that make sense for your domain/business logic
    latitude: parseAsFloat,
    longitude: parseAsFloat,
    zoomLevel: parseAsInteger
  },
  {
    // 2. Remap them to shorter keys in the URL
    urlKeys: {
      latitude: 'lat',
      longitude: 'lng',
      zoomLevel: 'z'
    }
  }
)

// 3. Use your variable names when calling the serializer,
// and the shorter keys will be rendered in the URL:
serialize({
  latitude: 45.18,
  longitude: 5.72,
  zoomLevel: 12
})
// ?lat=45.18&lng=5.72&z=12
```

### Processing URLSearchParams

<FeatureSupportMatrix introducedInVersion='2.6.0' />

Just like in the [`<NuqsAdapter>{:tsx}`](/docs/options#processing-urlsearchparams),
you can specify a `processUrlSearchParams{:ts}` function
to modify the search params before they are serialized.

For example, it can be useful for consistent canonical URLs (for SEO),
by sorting search param keys alphabetically:

```ts
// [!code word:processUrlSearchParams]
const serialize = createSerializer(
  {
    a: parseAsInteger,
    z: parseAsInteger
  },
  {
    processUrlSearchParams: (search) => {
      // Note: you can modify search in-place,
      // or return a copy, as you wish.
      search.sort()
      return search
    }
  }
)

serialize('?foo=bar', {
  a: 1,
  z: 1
})
// ?a=1&foo=bar&z=1
// merged, then sorted
```

## Parser type inference

<FeatureSupportMatrix introducedInVersion='1.18.0' />

To access the underlying type returned by a parser, you can use the
`inferParserType{:ts}` type helper:

```ts
import { parseAsInteger, type inferParserType } from 'nuqs' // or 'nuqs/server'

const intNullable = parseAsInteger
const intNonNull = parseAsInteger.withDefault(0)

inferParserType<typeof intNullable> // number | null
inferParserType<typeof intNonNull> // number
```

For an object describing parsers (that you'd pass to [`createLoader{:ts}`](/docs/server-side#loaders)
or to [`useQueryStates{:ts}`](/docs/batching#usequerystates)), `inferParserType{:ts}` will
return the type of the object with the parsers replaced by their inferred types:

```ts
import {
  parseAsBoolean,
  parseAsInteger,
  type inferParserType
} from 'nuqs' // or 'nuqs/server'

const parsers = {
  a: parseAsInteger,
  b: parseAsBoolean.withDefault(false)
}

inferParserType<typeof parsers>
// { a: number | null, b: boolean }
```

## Standard Schema

<FeatureSupportMatrix introducedInVersion='2.5.0' />

Search param definitions can be turned into a [Standard Schema](https://standardschema.dev)
for validating external sources and passing on type inference to other tools.

```ts
// [!code word:validateSearchParams]
import {
  createStandardSchemaV1,
  parseAsInteger,
  parseAsString,
} from 'nuqs' // or 'nuqs/server'

// 1. Define your search params as usual
export const searchParams = {
  searchTerm: parseAsString.withDefault(''),
  maxResults: parseAsInteger.withDefault(10)
}

// 2. Then create a Standard Schema compatible validator
export const validateSearchParams = createStandardSchemaV1(searchParams)

// 3. Use it with other tools, like tRPC:
router({
  search: publicProcedure.input(validateSearchParams).query(...)
})
```

### TanStack Router & validateSearch

You can pass the standard schema validator to
[TanStack Router](https://tanstack.com/router/)'s `validateSearch{:ts}` for type-safe
linking to nuqs URL state, but in order to keep those
values optional (as nuqs uses different defaults strategies
than TSR), you need to mark the output as `Partial{:ts}`,
using the `partialOutput{:ts}` option:

```ts title="src/routes/search.tsx"
// [!code word:partialOutput]
import { createStandardSchemaV1 } from 'nuqs'

const validateSearch = createStandardSchemaV1(searchParams, {
  partialOutput: true
})

export const Route = createFileRoute('/search')({
  validateSearch
})
```

<Callout title="Note" type="warn">
 TanStack Router support is still experimental and comes with caveats,
 see the [adapter documentation](/docs/adapters#tanstack-router) for more
 information about what is supported.
</Callout>
